import 'dart:async';
import 'dart:convert';

import 'package:star_author/env/env_config.dart';
import 'package:star_author/event_bus/global_event_bus.dart';
import 'package:star_author/utils/common_util/log_util.dart';
import 'package:star_author/utils/http/api_manager.dart';
import 'package:star_author/utils/user_util.dart';
import 'package:star_author/utils/websocket_manage/websocket_handler.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get/get.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

import '../../event_bus/socket_subscription_event.dart';

/// WebSocket状态
enum SocketStatus {
  SocketStatusConnected, // 已连接
  SocketStatusFailed, // 失败
  SocketStatusClosed, // 连接关闭
  SocketStatusUnConnected, //断开状态
}

class WebSocketManage {
  static WebSocketManage? _instance;

  WebSocketManage._() {
    // 具体初始化代码
  }

  factory WebSocketManage() {
    _instance ??= WebSocketManage._();
    return _instance!;
  }

  int socketDateTime = 0;

  IOWebSocketChannel? _webSocket; // WebSocket
  SocketStatus? _socketStatus; // socket状态
  Timer? _heartBeat; // 心跳定时器
  int _heartTimes = 5; // 心跳间隔(秒)
  int _reconnectCount = 720; // 默认重连次数，每秒5次相当于重连一小时
  int _reconnectTimes = 0; // 重连计数器
  Timer? _reconnectTimer; // 重连定时器

  //已经订阅的通知
  // 固定通知：NotificationChannel,HomeChannel,登录后才会订阅,不需要取消订阅
  // Map defaultSubscribeMap = {
  //   'NotificationChannel': jsonEncode({
  //     "command": "subscribe",
  //     "identifier": jsonEncode({"channel": "NotificationChannel"})
  //   }),
  //   'HomeChannel': jsonEncode({
  //     "command": "subscribe",
  //     "identifier": jsonEncode({"channel": "HomeChannel"})
  //   }),
  // };

  //动态订阅通知
  //直播间：StudioChannel等
  //订阅需要add,取消订阅移除
  Map flexibleSubscribeLMap = {};

  String baseUrl = WebSocketManage.getWSPath() + "/cable?user_id=";

  String? _socketUrl;

  void initWebSocket() {
    String userId = '';

    if (UserUtil.getUserId(Get.context!) != 0) {
      userId = UserUtil.getUserId(Get.context!).toString();
    }

    LogUtil.v("WebSocketManage initWebSocket");
    this._socketUrl = baseUrl + userId;
    connectSocket();
  }

  get socketStatus => _socketStatus;

  static String getWSPath() {
    String url = '';
    switch (EnvConfig.instance!.env) {
      case Env.DEV:
        url = ApiManager.WSDevUrl;
        break;
      case Env.TEST:
        url = ApiManager.WSProdUrl;
        break;
      case Env.PROD:
        url = ApiManager.WSProdUrl;
        break;
    }
    return url;
  }

  ///切换用户时候，更新userId,重连
  void changeConnectUrl(int id) {
    _socketUrl = baseUrl + id.toString();
    LogUtil.v('WebSocketManage WebSocket连接关闭 - changeConnectUrl(int id)');
    //移动直播间监听
    flexibleSubscribeLMap.remove('StudioChannel');
    connectSocket();
  }

  //isReconnect是否为重连
  //listen的onDone 一定要置null,防止多次重连
  void connectSocket() async {
    if (await connectionState() == false) {
      LogUtil.v('无网络服务 - reconnect');
      return;
    }
    closeSocket();
    _webSocket = IOWebSocketChannel.connect(_socketUrl!);
    _webSocket?.stream.listen(
      (event) {
        _webSocketOnMessage(event);
      },
      onError: webSocketOnError,
      onDone: null,
    );
    WebSocketManage().initHeartBeat();
  }

  webSocketOnError(e) {
    WebSocketChannelException ex = e;
    _socketStatus = SocketStatus.SocketStatusFailed;
    _onError(ex.message);
    LogUtil.v('WebSocketManage WebSocket连接关闭 - webSocketOnError(e)');
    closeSocket();
  }

  /// 初始化心跳
  void initHeartBeat() {
    destroyHeartBeat();
    _heartBeat = Timer.periodic(Duration(seconds: _heartTimes), (timer) {
      if ((_heartBeat?.isActive ?? false) == false) {
        timer.cancel();
        return;
      }
      sentHeart(timer);
    });
  }

  /// 心跳
  void sentHeart(Timer timer) {
    DateTime datetime =
        DateTime.fromMillisecondsSinceEpoch(socketDateTime * 1000);

    DateTime time_now = DateTime.now();
    bool isTimeout = time_now.difference(datetime).inSeconds > 60;

    // LogUtil.v(
    //     "WebSocketManage-检测socket链接状态,时差:${(DateTime.now().millisecondsSinceEpoch ~/ 1000) - socketDateTime}秒");
    if (isTimeout) {
      LogUtil.v("WebSocketManage->重连机制-sentHeart");
      timer.cancel();
      _socketStatus = SocketStatus.SocketStatusUnConnected;
      reconnect();
    }
  }

  /// 销毁心跳
  void destroyHeartBeat() {
    if (_heartBeat != null) {
      _heartBeat?.cancel();
      _heartBeat = null;
    }
  }

  /// 重连机制
  void reconnect() async {
    if (_socketStatus != SocketStatus.SocketStatusConnected) {
      if (_reconnectTimes < _reconnectCount) {
        _reconnectTimes++;
        _reconnectTimer =
            Timer.periodic(Duration(seconds: _heartTimes), (timer) {
          if ((_reconnectTimer?.isActive ?? false) == false) {
            timer.cancel();
            return;
          }
          LogUtil.v('WebSocketManage reconnect 重连机制${DateTime.now()}');
          connectSocket();
        });
      } else {
        if (_reconnectTimer != null) {
          LogUtil.v('WebSocketManage 重连次数超过最大次数');
          _reconnectTimer?.cancel();
          _reconnectTimer = null;
        }
        return;
      }
    }
  }

  /// 关闭WebSocket
  void closeSocket() {
    if (_webSocket != null) {
      LogUtil.v('WebSocketManage WebSocket连接关闭');
      _socketStatus = SocketStatus.SocketStatusClosed;
      _webSocket?.sink.close();
      destroyHeartBeat();
    }
  }

  Future<bool> connectionState() async {
    final connectionState = await Connectivity().checkConnectivity();
    if ([ConnectivityResult.wifi, ConnectivityResult.mobile]
        .contains(connectionState)) {
      return true;
    } else {
      return false;
    }
  }

  /// 发送WebSocket消息
  void sendMessage(String message) async {
    if (await connectionState() == false) {
      LogUtil.v('无网络服务');
      return;
    }
    if (_webSocket != null) {
      switch (_socketStatus) {
        case SocketStatus.SocketStatusConnected:
          LogUtil.v('WebSocketManage 发送中：' + message);
          _webSocket?.sink.add(message);
          break;
        case SocketStatus.SocketStatusClosed:
          LogUtil.v('WebSocketManage 连接已关闭');
          break;
        case SocketStatus.SocketStatusFailed:
          LogUtil.v('WebSocketManage 发送失败');
          break;
        default:
          break;
      }
    }
  }

  void _webSocketOnMessage(data) {
    Map result = json.decode(data);

    if (result["type"] == "ping") {
      LogUtil.v('result["type"]->${result["type"]}-${result["message"]}');
      socketDateTime = result["message"];
    }

    if (result["type"] != "ping") {
      //链接成功
      if (result["type"] == "welcome") {
        WebSocketManage()._onConnectSuccess();
      }
      LogUtil.v("WebSocketManage - onMessage $data");
      WebSocketHandle.socketNotificationSubscribe(Get.context!, result);

      try {
        ///发送通知
        GlobalEventBus().bus.fire(SocketSubscriptionEvent(result));
      } catch (e, t) {
        LogUtil.v(e);
        LogUtil.v(t);
      }
    }
  }

  //连接成功
  void _onConnectSuccess() {
    LogUtil.v('WebSocketManage WebSocket连接成功: $_socketUrl');

    // 连接成功，返回WebSocket实例
    _socketStatus = SocketStatus.SocketStatusConnected;
    // 连接成功，重置重连计数器
    _reconnectTimes = 0;
    if (_reconnectTimer != null) {
      LogUtil.v("WebSocketManage 取消重连倒计时");
      _reconnectTimer?.cancel();
      _reconnectTimer = null;
    }

    if (UserUtil.isLogin(Get.context!)) {
      LogUtil.v("WebSocketManage WebSocket连接成功 -> 发送通知");

      flexibleSubscribeLMap.forEach((key, value) {
        LogUtil.v(
            "WebSocketManage->重连->重新订阅通知 ->flexibleSubscribeLMap.forEach$key-$value");
        sendMessage(value);
      });
    }
  }

  void _onError(e) {
    LogUtil.v("WebSocketManage - onError $e");
  }
}
